package hawk.example.bookstore.repository.impl;

import static glz.hawkframework.support.ArgumentSupport.*;

import glz.hawkframework.dao.base.process.InsertProcessor;
import glz.hawkframework.dao.base.process.UpdateProcessor;
import glz.hawkframework.sql.condition.Condition;
import glz.hawkframework.sql.util.QueryWrapper;

import hawk.example.bookstore.mapper.BookAuthorMapMapper;
import hawk.example.bookstore.po.BookAuthorMapPo;
import hawk.example.bookstore.repository.BookAuthorMapRepository;
import hawk.example.bookstore.sql.provider.BookAuthorMapSqlProvider;
import hawk.example.bookstore.update.BookAuthorMapColumnUpdate;
import hawk.example.bookstore.update.BookAuthorMapUpdate;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import javax.annotation.Nullable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class BookAuthorMapRepositoryImpl implements BookAuthorMapRepository {
    private final BookAuthorMapMapper bookAuthorMapMapper;
    private final BookAuthorMapSqlProvider bookAuthorMapSqlProvider;
    @Autowired(required = false)
    private InsertProcessor insertProcessor;
    @Autowired(required = false)
    private UpdateProcessor updateProcessor;

    public BookAuthorMapRepositoryImpl(BookAuthorMapMapper bookAuthorMapMapper, BookAuthorMapSqlProvider bookAuthorMapSqlProvider) {
        this.bookAuthorMapMapper = argNotNull(bookAuthorMapMapper, "bookAuthorMapMapper");
        this.bookAuthorMapSqlProvider = argNotNull(bookAuthorMapSqlProvider, "bookAuthorMapSqlProvider");
    }

    @Override
    public void insert(BookAuthorMapPo bookAuthorMapPo) {
        argNotNull(bookAuthorMapPo, "bookAuthorMapPo");
        if (insertProcessor != null) {
            insertProcessor.beforeInsert(bookAuthorMapPo);
        }
        if (bookAuthorMapMapper.insert(bookAuthorMapSqlProvider.insert(bookAuthorMapPo)) != 1) {
            throw new IllegalStateException("Failed to insert bookAuthorMapPo.");
        }
        if (insertProcessor != null) {
            insertProcessor.afterInsert(bookAuthorMapPo);
        }
    }

    @Override
    public void insertSelective(BookAuthorMapPo bookAuthorMapPo) {
        argNotNull(bookAuthorMapPo, "bookAuthorMapPo");
        if (insertProcessor != null) {
            insertProcessor.beforeInsert(bookAuthorMapPo);
        }
        if (bookAuthorMapMapper.insertSelective(bookAuthorMapSqlProvider.insertSelective(bookAuthorMapPo)) != 1) {
            throw new IllegalStateException("Failed to insert bookAuthorMapPo.");
        }
        if (insertProcessor != null) {
            insertProcessor.afterInsert(bookAuthorMapPo);
        }
    }

    @Override
    public void insertMultiple(List<BookAuthorMapPo> bookAuthorMapPos) {
        final int defaultChunkSize = 200;
        insertMultiple(bookAuthorMapPos, defaultChunkSize);
    }

    @Override
    public void insertMultiple(List<BookAuthorMapPo> bookAuthorMapPos, int chunkSize) {
        argNotEmpty(bookAuthorMapPos, "bookAuthorMapPos");
        argument(chunkSize, c -> c > 0, c -> "The parameter['chunkSize'] must be greater than 0.");
        for (int i = 0; i < bookAuthorMapPos.size(); i += chunkSize) {
            List<BookAuthorMapPo> chunk = bookAuthorMapPos.subList(i, Math.min(i + chunkSize, bookAuthorMapPos.size()));
            if (insertProcessor != null) {
                insertProcessor.beforeInsert(chunk);
            }
            if (bookAuthorMapMapper.insertMultiple(bookAuthorMapSqlProvider.insertMultiple(chunk)) != chunk.size()) {
                throw new IllegalStateException("Failed to insert bookAuthorMapPos.");
            }
            if (insertProcessor != null) {
                insertProcessor.afterInsert(chunk);
            }
        }
    }

    @Override
    public void deleteByPrimaryKey(BigInteger bookAuthorMapId, Long recordVersion) {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        argNotNull(recordVersion, "recordVersion");
        if (bookAuthorMapMapper.deleteGeneral(bookAuthorMapSqlProvider.deleteByPrimaryKey(bookAuthorMapId, recordVersion)) != 1) {
            throw new IllegalStateException("Failed to delete bookAuthorMapPo.");
        }
    }

    @Override
    public void updateByPrimaryKey(BookAuthorMapUpdate bookAuthorMapUpdate, BigInteger bookAuthorMapId, Long recordVersion) {
        argNotNull(bookAuthorMapUpdate, "bookAuthorMapUpdate");
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        argNotNull(recordVersion, "recordVersion");
        HashMap<String, Object> params = null;
        if (updateProcessor != null) {
            params = new HashMap<>();
            params.put(UpdateProcessor.UPDATE_BY_FIELD_OBJECT, bookAuthorMapUpdate);
            params.put(UpdateProcessor.RECORD_VERSION, recordVersion);
            params.put(UpdateProcessor.RECORD_ID, bookAuthorMapId);
            updateProcessor.beforeUpdate(params);
        }
        if (bookAuthorMapMapper.update(bookAuthorMapSqlProvider.updateByPrimaryKey(bookAuthorMapUpdate, bookAuthorMapId, recordVersion)) != 1) {
            throw new IllegalStateException("Failed to update bookAuthorMapPo.");
        }
        if (updateProcessor != null) {
            updateProcessor.afterUpdate(params);
        }
    }

    @Override
    public Optional<BookAuthorMapPo> getByPrimaryKey(BigInteger bookAuthorMapId) {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectByPrimaryKey(bookAuthorMapId));
    }

    /**
     * Throws an exception if found no required record by the primary key.
     */
    @Override
    public BookAuthorMapPo loadByPrimaryKey(BigInteger bookAuthorMapId) {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectByPrimaryKey(bookAuthorMapId)).orElseThrow(RuntimeException::new);
    }

    /**
     * Throws the supplied exception if found no required record by the primary key.
     */
    @Override
    public <E extends Throwable> BookAuthorMapPo loadByPrimaryKey(BigInteger bookAuthorMapId, Supplier<? extends E> exceptionSupplier) throws E {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        argNotNull(exceptionSupplier, "exceptionSupplier");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectByPrimaryKey(bookAuthorMapId)).orElseThrow(exceptionSupplier);
    }

    @Override
    public boolean existByPrimaryKey(BigInteger bookAuthorMapId) {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        return bookAuthorMapMapper.count(bookAuthorMapSqlProvider.countByPrimaryKey(bookAuthorMapId)) == 1;
    }

    /**
     * Throws an exception if the required record doesn't exist
     */
    @Override
    public void assertExistByPrimaryKey(BigInteger bookAuthorMapId) {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.countByPrimaryKey(bookAuthorMapId)) != 1) {
            throw new RuntimeException("Record not exist");
        }
    }

    /**
     * Throws the supplied exception if the required record doesn't exist
     */
    @Override
    public <E extends Throwable> void assertExistByPrimaryKey(BigInteger bookAuthorMapId, Supplier<? extends E> exceptionSupplier) throws E {
        argNotNull(bookAuthorMapId, "bookAuthorMapId");
        argNotNull(exceptionSupplier, "exceptionSupplier");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.countByPrimaryKey(bookAuthorMapId)) != 1) {
            throw exceptionSupplier.get();
        }
    }

    @Override
    public Optional<BookAuthorMapPo> queryOne(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), q -> !q.isCount(), q -> "The count field in the queryWrapper should be set to false.");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper));
    }

    @Override
    public List<BookAuthorMapPo> queryMany(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), q -> !q.isCount(), q -> "The count field in the queryWrapper should be set to false.");
        return bookAuthorMapMapper.selectMany(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper));
    }

    /**
     * Throws an exception if found no required record.
     */
    @Override
    public BookAuthorMapPo loadOne(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), q -> !q.isCount(), q -> "The count field in the queryWrapper should be set to false.");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)).orElseThrow(RuntimeException::new);
    }

    /**
     * Throws the supplied exception if found no required record.
     */
    @Override
    public <E extends Throwable> BookAuthorMapPo loadOne(QueryWrapper queryWrapper, Supplier<? extends E> exceptionSupplier) throws E {
        argument(argNotNull(queryWrapper, "queryWrapper"), q -> !q.isCount(), q -> "The count field in the queryWrapper should be set to false.");
        argNotNull(exceptionSupplier, "exceptionSupplier");
        return bookAuthorMapMapper.selectOne(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)).orElseThrow(exceptionSupplier);
    }

    @Override
    public long count(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        return bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper));
    }

    @Override
    public boolean exist(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        return bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) > 0;
    }

    /**
     * Throws an exception if found no required record.
     */
    @Override
    public void assertExist(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) <= 0) {
            throw new RuntimeException();
        }
    }

    /**
     * Throws the supplied exception if found no required record.
     */
    @Override
    public <E extends Throwable> void assertExist(QueryWrapper queryWrapper, Supplier<? extends E> exceptionSupplier) throws E {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        argNotNull(exceptionSupplier, "exceptionSupplier");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) <= 0) {
            throw exceptionSupplier.get();
        }
    }

    @Override
    public boolean existOne(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        return bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) == 1;
    }

    /**
     * Throws an exception if found no required record or found more than one record.
     */
    @Override
    public void assertExistOne(QueryWrapper queryWrapper) {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) == 0) {
            throw new RuntimeException();
        }
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) > 1) {
            throw new RuntimeException();
        }
    }

    /**
     * Throws the supplied exception if found no required record or found more than one record.
     */
    @Override
    public <E extends Throwable> void assertExistOne(QueryWrapper queryWrapper, Supplier<? extends E> exceptionSupplier) throws E {
        argument(argNotNull(queryWrapper, "queryWrapper"), QueryWrapper::isCount, q -> "The count field in the queryWrapper should be set to true.");
        argNotNull(exceptionSupplier, "exceptionSupplier");
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) == 0) {
            throw exceptionSupplier.get();
        }
        if (bookAuthorMapMapper.count(bookAuthorMapSqlProvider.selectOrCountDynamic(queryWrapper)) > 1) {
            throw exceptionSupplier.get();
        }
    }

    @Override
    public long delete(@Nullable Condition condition) {
        return bookAuthorMapMapper.deleteGeneral(bookAuthorMapSqlProvider.deleteDynamic(condition));
    }

    @Override
    public long update(BookAuthorMapColumnUpdate bookAuthorMapColumnUpdate, @Nullable Condition condition) {
        argNotNull(bookAuthorMapColumnUpdate,"bookAuthorMapColumnUpdate");
        HashMap<String, Object> params = null;
        if (updateProcessor != null) {
            params = new HashMap<>();
            params.put(UpdateProcessor.UPDATE_BY_COLUMN_OBJECT, bookAuthorMapColumnUpdate);
            updateProcessor.beforeUpdate(params);
        }
        long affectedRowCount =  bookAuthorMapMapper.updateGeneral(bookAuthorMapSqlProvider.updateDynamic(bookAuthorMapColumnUpdate, condition));
        if (updateProcessor != null) {
            updateProcessor.afterUpdate(params);
        }
        return affectedRowCount;
    }
}
